package cn.com.connext.scrm.service;

import cn.com.connext.scrm.config.Constants;
import cn.com.connext.scrm.domain.master.BuryingPointAd;
import cn.com.connext.scrm.repository.master.BuryingPointAdRepository;
import cn.com.connext.scrm.utils.RedisUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.transaction.Transactional;
import java.util.*;

@Service
@Transactional
public class MarketingService {
    // 腾讯广告数据上报取得数据源
    private static final String UASAURLGET = "https://api.e.qq.com/v1.1/user_action_sets/get?access_token=ACCESS_TOKEN&timestamp=TIMESTAMP&nonce=NONCE&account_id=ACCOUNTID&type=TYPE";
    // 腾讯广告数据上报创建数据源
    private static final String UASAURLADD = "https://api.e.qq.com/v1.1/user_action_sets/add?access_token=ACCESS_TOKEN&timestamp=TIMESTAMP&nonce=NONCE";
    // 腾讯广告数据上报回传数据
    private static final String UAAURLADD = "https://api.e.qq.com/v1.1/user_actions/add?access_token=ACCESS_TOKEN&timestamp=TIMESTAMP&nonce=NONCE";
    // 腾讯广告授权认证
    private static final String AUTHORIZE = "https://developers.e.qq.com/oauth/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI";
    // 腾讯广告授权认证刷新AccessToken
    private static final String OAUTHTOKENREFRESH = "https://api.e.qq.com/oauth/token?client_id=CLIENTID&client_secret=CLIENTSECRET&grant_type=GRANTTYPE&refresh_token=REFRESHTOKEN";
    // 腾讯广告授权认证通过AuthorizationCode获取AccessToken
    private static final String OAUTHTOKENBYAUTHORIZATIONCODE = "https://api.e.qq.com/oauth/token?client_id=CLIENTID&client_secret=CLIENTSECRET&grant_type=GRANTTYPE&authorization_code=AUTHORIZATIONCODE&redirect_uri=REDIRECT_URI";
    // 腾讯广告推广帐号 id
    private final String accountId = "19784749";
    // 腾讯广告应用 id
    private final int clientId = 1111857882;
    // 腾讯广告应用 secret
    private final String clientSecret = "ClWJdarxHBUOSAAh";
    // 临时刷新token
    private final String refreshTokenTemp = "3469fcdb9effbcc988e937f7577e9af0";

    private final Logger log = LoggerFactory.getLogger(MarketingService.class);

    private RestTemplate restTemplate = new RestTemplate();

    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private BuryingPointAdRepository buryingPointAdRepository;

    /**
     * 转化跟踪
     */
    public String getUserActionsByClickID(String clickId, String phone) {
        String result = "";

        //数据不为空回传数据
        if (null != clickId) {
            Object oauthAccessTokenO = redisUtils.get("OauthAccessToken");
            String accessToken = "";
            if (oauthAccessTokenO != null) {
                accessToken = oauthAccessTokenO.toString();
            } else {
                redisUtils.remove("getUserActionsClickId");
                redisUtils.remove("getUserActionsPhone");
                redisUtils.set("getUserActionsClickId", clickId, 60L);
                redisUtils.set("getUserActionsPhone", phone, 60L);
                // 通过刷新token，获取accessToken
                accessToken = getAccessTokenRefresh();
                if (accessToken.isEmpty() || ("").equals(accessToken)) {
                    return "accessToken取得失败";
                }
            }
            // 上传数据
            result = addUserActions(accessToken, clickId, phone);
        }

        return result;
    }

    /**
     * 先授权认证取得AccessToken，再做用户行为数据上传
     */
    public String getUserActionsByAuthorizationCode(String authorization_code) {
        String result = "";
        //数据不为空回传数据
        if (null != authorization_code) {
            // 通过 Authorization Code 获取 Access Token
            String accessToken = getAccessTokenByAuthorizationCode(authorization_code, Constants.redirectUri);

            String clickId = redisUtils.get("getUserActionsClickId").toString();
            String phone = redisUtils.get("getUserActionsPhone").toString();
            // 上传数据
            result = addUserActions(accessToken, clickId, phone);

        }
        return result;
    }

    /**
     * 初次授权认证
     */
    public String getUserActionsWithAuthorizationCode(String authorization_code) {
        String result = "";
        //数据不为空回传数据
        if (null != authorization_code) {
            // 通过 Authorization Code 获取 Access Token
            String accessToken = getAccessTokenByAuthorizationCode(authorization_code, Constants.redirectUriFst);

            if (accessToken.isEmpty() || "".equals(accessToken)) {
                result = "授权失败";
            } else {
                result = "授权成功";
            }
        }
        return result;
    }

    /**
     * 刷新AccessToken
     */
    public String getAccessTokenRefresh() {
        String accessToken = "";
        String refreshAccessToken = "";
        Object oauthRefreshTokenO = redisUtils.get("OauthRefreshToken");
        if (oauthRefreshTokenO != null) {
            refreshAccessToken = oauthRefreshTokenO.toString();
        } else {
            refreshAccessToken = refreshTokenTemp;
        }
        String requestUrl = OAUTHTOKENREFRESH.replace("CLIENTID", String.valueOf(clientId))
            .replace("CLIENTSECRET", clientSecret)
            .replace("GRANTTYPE", "refresh_token")
            .replace("REFRESHTOKEN", refreshAccessToken);
        log.info(" 刷新AccessToken请求参数 = {} ", requestUrl);
        JSONObject result = restTemplate.getForEntity(requestUrl, JSONObject.class).getBody();
        log.info(" 刷新AccessToken请求结果 = {} ", result);
        if ("0".equals(result.getString("code"))) {

            accessToken = result.getJSONObject("data").getString("access_token");
            Long accessTokenExpiresIn = result.getJSONObject("data").getLong("access_token_expires_in");
            redisUtils.remove("OauthAccessToken");
            redisUtils.remove("OauthRefreshToken");
            redisUtils.set("OauthAccessToken", accessToken, accessTokenExpiresIn);
            redisUtils.set("OauthRefreshToken", refreshAccessToken, accessTokenExpiresIn * 30L);
        }
        // 通过刷新refresh_token的方式未获取accessToken时，需要通过AuthorizationCode获取AccessToken和refreshToken
        if (accessToken.isEmpty() || "".equals(accessToken)) {
            getAuthorizationCode();
        }

        return accessToken;
    }

    /**
     * 通过 Authorization Code 获取 Access Token
     */
    private String getAccessTokenByAuthorizationCode(String authorizationCode, String redirectUriStr) {
        // 第一步获取 Access Token接口
        String requestUrl = OAUTHTOKENBYAUTHORIZATIONCODE.replace("CLIENTID", String.valueOf(clientId))
            .replace("CLIENTSECRET", clientSecret)
            .replace("GRANTTYPE", "authorization_code")
            .replace("AUTHORIZATIONCODE", authorizationCode)
            .replace("REDIRECT_URI", redirectUriStr);
        log.info(" 通过AuthorizationCode 获取 AccessToken请求参数 = {} ", requestUrl);
        JSONObject result = restTemplate.getForEntity(requestUrl, JSONObject.class).getBody();
        log.info(" 通过AuthorizationCode 获取 AccessToken请求结果 = {} ", result);
        String accessToken = "";
        if ("0".equals(result.getString("code"))) {
            accessToken = result.getJSONObject("data").getString("access_token");
            Long accessTokenExpiresIn = result.getJSONObject("data").getLong("access_token_expires_in");
            String refreshToken = result.getJSONObject("data").getString("refresh_token");
            Long refreshTokenExpiresIn = result.getJSONObject("data").getLong("refresh_token_expires_in");
            redisUtils.remove("OauthAccessToken");
            redisUtils.remove("OauthRefreshToken");
            redisUtils.set("OauthAccessToken", accessToken, accessTokenExpiresIn);
            redisUtils.set("OauthRefreshToken", refreshToken, refreshTokenExpiresIn);
        }
        return accessToken;
    }

    /**
     * 取得Authorization Code
     */
    private void getAuthorizationCode() {
        // 通过授权认证取得AuthorizationCode
        String requestUrl = AUTHORIZE.replace("CLIENT_ID", String.valueOf(clientId))
            .replace("REDIRECT_URI", Constants.redirectUri);
        log.info(" 通过授权认证取得AuthorizationCode请求参数 = {} ", requestUrl);
        restTemplate.getForEntity(requestUrl, String.class);
    }

    /**
     * 取得数据源
     */
    private int getUserActionSetId(String accessToken, String nonce) {

        // 用户行为源id
        int userActionsetId = 0;
        // 调用数据源接口get方法，用账户取得数据源，如果没有，再调用add方法创建
        String requestUrl = UASAURLGET.replace("ACCESS_TOKEN", accessToken)
            .replace("TIMESTAMP", String.valueOf(System.currentTimeMillis()/1000))
            .replace("NONCE", nonce)
            .replace("ACCOUNTID", accountId)
            .replace("TYPE","[\"WEB\"]");
        log.info(" 取得数据源请求参数 = {} ", requestUrl);
        ResponseEntity<JSONObject> result = restTemplate.getForEntity(requestUrl, JSONObject.class);
        log.info("取得数据源请求 = {}", result);
        if ("0".equals(result.getBody().getString("code"))
            && result.getBody().getJSONObject("data").getJSONArray("list").size() > 0) {
            userActionsetId = result.getBody().getJSONObject("data").getJSONArray("list").getJSONObject(0).getIntValue("user_action_set_id");
        }
        if (userActionsetId == 0) {
            userActionsetId = addUserActionSetId(accessToken, UUID.randomUUID().toString().replace("-", ""));
        }

        return userActionsetId;
    }

    /**
     * 创建数据源
     */
    private int addUserActionSetId(String accessToken, String nonce) {
        // 调用数据源接口add方法创建
        String requestUrl = UASAURLADD.replace("ACCESS_TOKEN", accessToken)
            .replace("TIMESTAMP", String.valueOf(System.currentTimeMillis()).substring(0, 10))
            .replace("NONCE", nonce);
        JSONObject requestBody = new JSONObject();
        requestBody.put("account_id", accountId);
        requestBody.put("type", "WEB");
        requestBody.put("name", "webuser_action_set");
        log.info("创建数据源请求参数 = {}", requestBody.toString());
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        HttpEntity<String> formUserActionsSetsEntity = new HttpEntity<String>(requestBody.toString(), headers);
        ResponseEntity<JSONObject> result = restTemplate.postForEntity(requestUrl, formUserActionsSetsEntity, JSONObject.class);
        log.info("创建数据源请求结果 = {}", result);
        // 用户行为源id
        int userActionsetId = 0;
        if ("0".equals(result.getBody().getString("code"))) {
            userActionsetId = result.getBody().getJSONObject("data").getIntValue("user_action_set_id");
        }
        return userActionsetId;
    }

    /**
     * 数据上报
     */
    private String addUserActions(String accessToken, String clickId, String phone) {

        // 用户行为源id
        int userActionsetId = getUserActionSetId(accessToken, UUID.randomUUID().toString().replace("-", ""));
        if (userActionsetId == 0) {
            return "用户行为源信息取得失败";
        }
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());

        //调用外部接口--转化跟踪回传数据
        String requestUrl = UAAURLADD.replace("ACCESS_TOKEN", accessToken)
            .replace("TIMESTAMP", String.valueOf(System.currentTimeMillis()/1000))
            .replace("NONCE", UUID.randomUUID().toString().replace("-", ""));
        JSONObject requesBody = new JSONObject();
        requesBody.put("account_id", accountId);
        requesBody.put("user_action_set_id", String.valueOf(userActionsetId));

        JSONArray actionsArray = new JSONArray();
        JSONObject actionsInfo = new JSONObject();

        actionsInfo.put("action_time", System.currentTimeMillis()/1000);
        actionsInfo.put("action_type", "RESERVATION");
        JSONObject clickIdInfo = new JSONObject();
        clickIdInfo.put("click_id", clickId);
        actionsInfo.put("trace", clickIdInfo);
        actionsInfo.put("url", "https://wxadmin.singlemalts.com.cn/page/reward/newActivity/index?activityId=401746f9-6f59-490b-a142-e690a2601d6e");

        JSONObject actionParamInfo = new JSONObject();
        actionParamInfo.put("phone", phone);
        actionsInfo.put("action_param", actionParamInfo);
        actionsArray.add(actionsInfo);
        requesBody.put("actions", actionsArray);

        log.info("转化跟踪回传数据请求参数 = {}", requesBody.toString());
        HttpEntity<String> formEntity = new HttpEntity<String>(requesBody.toString(), headers);
        ResponseEntity<JSONObject>  result = restTemplate.postForEntity(requestUrl, formEntity, JSONObject.class);
        log.info("转化跟踪回传数据信息请求结果 = {}", result.getBody());
        // 上报数据成功时，将上报数据保存到表中
        if ("0".equals(result.getBody().getString("code"))) {
            BuryingPointAd buryingPointAd = new BuryingPointAd();
            buryingPointAd.setUserActionSetId(userActionsetId);
            buryingPointAd.setClickId(clickId);
            buryingPointAd.setActionType("RESERVATION");
            buryingPointAd.setUrl("https://wxadmin.singlemalts.com.cn/page/reward/newActivity/index?activityId=401746f9-6f59-490b-a142-e690a2601d6e");
            buryingPointAd.setActionTime(new Date());
            buryingPointAd.setActionParamPhone(phone);
            buryingPointAdRepository.save(buryingPointAd);

        }
        return result.getBody().getString("message_cn");
    }
}
